home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_sys5 / unixkit.tgz / unixkit.tar / unixkit / thread / bsdunix.c next >
C/C++ Source or Header  |  1991-12-18  |  21KB  |  913 lines

  1. /*            NOS porting kit for 4.3 BSD UNIX
  2.  *                    890407
  3.  *
  4.  *            Updated by KA9WSB Nov 91
  5.  *
  6.  * The following text is the original text and does not reflect the
  7.  * current changes/environment for NOS and the porting kit.  Refer to
  8.  * the README file for the current descriptions and documentation. KA9WSB
  9.  *
  10.  * ----------------------------------------------------------------------
  11.  *
  12.  * Files are: bsdunix.c, asy.h, bsdksubr.c, bsd_io.c, bsd_nit.c, bsd_tun.c,
  13.  * Makefile.bsd
  14.  *
  15.  * This runs on a SUN-3 and on a NeXT, I have not tested it elsewhere.
  16.  * Do not forget to change the definition of JB_SP in bsdksubr.c as required.
  17.  *
  18.  * The NIT and TUN drivers are activated by defining PACKET in config.h but
  19.  * you need to run NOS as root to use them. TUN is the more efficient, so
  20.  * I recommend its usage over NIT.
  21.  *
  22.  * You need release 891022 or later of KA9Q NOS to use these files.
  23.  *
  24.  * You should insert a "stksize += 2000;" or so in newproc() in kernel.c,
  25.  * since more stack space is needed on 32 bit machines. Also change the
  26.  * stack assignment to use int's instead of int16's, if you have a 32 bit CPU.
  27.  *
  28.  * You will probably like to increase the definition of MSPTICK in timer.c
  29.  * somewhat, such as doubling it.
  30.  *
  31.  * Delete any lines in hardware.h that causes compiler errors. You may
  32.  * run into other compiler errors as well, caused by differences between
  33.  * Turbo-C and UNIX compilers, but they should not be too hard to fix.
  34.  *
  35.  * You need to modify global.h somewhat. This is how I have done:
  36.  *
  37.    typedef int int32;
  38.    typedef unsigned short int16;
  39.  
  40.    - - -
  41.    #define callocw(x,y)    calloc(x,y)
  42.    #define mallocw(x)    malloc(x)
  43.    #define availmem()    (long)Memthresh
  44.    #define ptol(p)        (long)p
  45.    #define ltop(p)        (p)
  46.  
  47.    #ifdef tolower(c)
  48.    #undef tolower(c)
  49.    #endif
  50.    #ifdef UNIX
  51.    extern int (*xxfree)();
  52.    #define free(p)        ((char *)p != NULLCHAR ? (*xxfree)(p) : 0)
  53.    extern char *sys_errlist[];
  54.    extern int errno;
  55.    #endif
  56.    char *malloc();
  57.  *
  58.  * The above definition is needed when one doesn't use alloc.c. The BSD
  59.  * free() doesn't check if the argument is a pointer to NULL.
  60.  * It seems to be ok not to use alloc.c as long as no calls to malloc()
  61.  * etc are done at interrupt level.
  62.  * 
  63.  * Written by Anders Klemets, SM0RGV, klemets@sics.se
  64.  * (a few functions at the end were written by Mikel Matthews, N9DVG
  65.  *  Jere Sandidge, K4FUM, and some others.)
  66.  * I would appreciate to see any improvements you make.
  67.  *
  68.  */
  69. #include <stdio.h>
  70. #include <sys/types.h>
  71. #include <signal.h>
  72. #include <fcntl.h>
  73. #include <sys/ioctl.h>
  74. #include <sys/time.h>
  75. #include <sys/resource.h>
  76. #include <sys/stat.h>
  77. #include <sys/param.h>
  78. #include <dirent.h>
  79. #include <ctype.h>
  80.  
  81.  /*   KA9WSB
  82.   * free handling...
  83.   * This is grungy 'cause free() in most unix machines pukes if handed
  84.   * a null pointer.  So we have to check.  The "easy" way is to define
  85.   * a variable named "xxfree" which is an indirect pointer to the real
  86.   * system free().  Then, in "global.h", we define free to be a macro:
  87.   *      ((char *)p != NULLCHAR ? (*xxfree)(p) : 0)
  88.   * Neat huh??
  89.   * Only one problem -- code like this:
  90.   *      free(*argv++);
  91.   * fails!  Why?  Well, it translates to:
  92.   *      ((char *)*argv++ != NULLCHAR ? (*xxfree)(*argv++) : 0)
  93.   * which increments argv twice; the first time by one byte,
  94.   * the second time by whatever argv is declared to be! (this
  95.   * little gem was gleaned from kernel.c; it ended up incrementing
  96.   * argv by 5 bytes instead of 4)  To solve this problem, you are
  97.   * offered two choices:  search for all every occurence of "free"
  98.   * in all the c sources (grep works nicely), and verify that none
  99.   * will break if expanded into the above macro.  Or, add the
  100.   * following flag to the CCFLAGS line in the makefile:
  101.   * -DBULLET_PROOF_FREE
  102.   *
  103.   */
  104. int free();         /* This must be before we include global.h */
  105. #ifndef BULLET_PROOF_FREE
  106. int (*xxfree)() = free; /* if we are not using alloc.c */
  107. #else
  108. int xyfree(q) char *q;{if(q)return free(q);else return 0;}
  109. #endif
  110.  
  111. #include "global.h"
  112. #include "config.h"
  113. #include "iface.h"
  114. #include "proc.h"
  115. #include "timer.h"
  116. #include "session.h"
  117. #include "asy.h"
  118. #include "hardware.h"
  119.  
  120. static void timerint(),inpint();
  121. void iostop();
  122. int32 Clock, StartSec, StartUsec;
  123. int Tick, console;
  124. FILE *Rawterm = stdout;
  125. struct sgttyb mysavetty, savecon;
  126. int console_saved = 0;
  127. int WDTick, WDCurr;
  128.  
  129. #ifndef NO_INTSTK
  130. int16 Intstk[INTSTK_SIZE];        /* The signal stack */
  131. #endif
  132.  
  133. /* Interface list header */
  134. struct iface *Ifaces;
  135.  
  136. /* Keyboard input buffer */
  137. struct fifo Keyboard;
  138.  
  139. extern struct proc *Display;
  140.  
  141. int shell=0,intoff=0,inputpending=0,ownpid;
  142.  
  143.  /*  KA9WSB
  144.   *  define MALLOCDEBUG in the makefile to use the malloc debugging stuff.
  145.   *  Note that if you do this, you will have to load /usr/lib/debug/malloc.o
  146.   *  before libc in the makefile...
  147.   *  This is probably a VERY good thing to do, given NOS' tendency to abuse
  148.   *  memory :-)
  149.   */
  150. #ifdef MALLOCDEBUG
  151. int malloc_debug();    /* in the /usr/lib/debug/malloc.o library */
  152. int malloc_verify();    /* in the /usr/lib/debug/malloc.o library */
  153. #endif
  154.  
  155.  /* KA9WSB
  156.   * Debugging trick... #define QUERY_INPUT and NOS will check the NOS_TTY
  157.   * environment variable for the device to use for input... thus making
  158.   * it possible to debug NOS under dbxtool.  Fire up another shelltool,
  159.   * use the tty command to find out the tty name (something like 
  160.   * /dev/ttyp2), and then type "sleep 30000" to make the shell in that
  161.   * window go away.  Now in another shelltool type "setenv NOS_TTY
  162.   * /dev/ttyp2", fire up dbxtool with nos in it, type "ignore IO" 
  163.   * (so dbxtool will let nos handle the SIGIO envents, and type "run".
  164.   * NOS will now be happily taking input from the sleeping window.
  165.   */
  166. #define QUERY_INPUT
  167.  
  168. /* Called at startup time to set up console I/O, memory heap */
  169. void
  170. ioinit()
  171. {
  172.     struct sgttyb ttybuf;
  173.     struct timeval tp;
  174.     char *ttydev;
  175. #ifndef NO_INTSTK
  176.         struct sigstack ss;
  177.     struct sigvec sv;
  178. #endif
  179.  
  180. #ifdef MALLOCDEBUG
  181. #ifndef MALLOCDEBUG_LEVEL
  182. #define MALLOCDEBUG_LEVEL 2
  183. #endif
  184.     (void)malloc_debug(MALLOCDEBUG_LEVEL);
  185. #endif
  186.  
  187.     /* begin by recording the start time as NOW */
  188.     gettimeofday(&tp,NULL);
  189.     StartSec = tp.tv_sec;
  190.     StartUsec = tp.tv_usec;
  191.     Clock = 0;
  192.  
  193.     /* We want unbuffered output */
  194.     if(isatty(1)) {
  195. #ifndef BUFFERED_OUTPUT
  196.         freopen(ttyname(1),"w",stdout);
  197.         setbuf(stdout,NULLCHAR);
  198. #endif
  199.  
  200. #ifdef QUERY_INPUT
  201.         ttydev = getenv("NOS_TTY");
  202.         if(ttydev==NULL) ttydev = "/dev/tty";
  203. #else
  204.         ttydev = "/dev/tty";
  205. #endif
  206.         if ((console = open(ttydev,O_RDONLY|O_NDELAY)) < 0) {
  207.         perror(ttydev);
  208.         exit(1);
  209.         }
  210.         ioctl(console,TIOCGETP,&ttybuf);
  211.         savecon = ttybuf;
  212.         ttybuf.sg_flags &= ~ECHO;
  213.         ttybuf.sg_flags |= CBREAK;
  214.         ioctl(console,TIOCSETP,&ttybuf);
  215.         console_saved = 1;
  216.     }
  217.     else console = 0;
  218.  
  219.     (void) signal(SIGHUP, iostop);
  220.     (void) signal(SIGINT, iostop);
  221.     (void) signal(SIGQUIT, iostop);
  222.     (void) signal(SIGTERM, iostop);
  223.  
  224.     /* Initialize keyboard queue */
  225.     Keyboard.bufsize = 256;
  226.     Keyboard.buf = malloc (256);
  227.     Keyboard.rp = Keyboard.wp = Keyboard.buf;
  228.  
  229.     /* Create the signal stack.
  230.        Note that if you don't use one, you may have to make the
  231.            process's stacks considerably larger.  Watch out for
  232.            alignment on the signal stack */
  233. #ifndef NO_INTSTK
  234.     ss.ss_sp = (char *)((int)&Intstk[(INTSTK_SIZE-1)] & 0xfffffff8);
  235.     ss.ss_onstack = 0;
  236.     sigstack (&ss, (struct sigstack *)0);
  237.  
  238.     /* Set up interrupts. If your system doesn't support sigvec(),
  239.        you may skip the signal stack stuff and use signal() instead. */
  240.     
  241.     sv.sv_flags = SV_ONSTACK; /* We want to execute on the signal stack */
  242.  
  243.     sv.sv_handler = timerint;
  244.     sv.sv_mask = sigmask(SIGALRM);
  245.     sigvec(SIGALRM,&sv,(struct sigvec *)0);
  246.  
  247.     sv.sv_handler = inpint;
  248.     sv.sv_mask = sigmask(SIGIO);
  249.     sigvec(SIGIO,&sv,(struct sigvec *)0);
  250. #else
  251.     signal(SIGALRM,timerint);
  252.     signal(SIGIO, inpint);
  253. #endif
  254.  
  255.     /* Get the process ID of this program, we might want to kill
  256.        ourselves later. */
  257.     ownpid = getpid();
  258.  
  259.     /* This will send a SIGIO signal whenever a key is pressed and
  260.        the stdin queue is empty. It would be better if the signal would
  261.        always be sent, regardless of the status of the queue. */
  262.     if(isatty(console)) {
  263.         fcntl(console,F_SETFL, fcntl(console,F_GETFL,0) | FASYNC);
  264.         fcntl(console,F_SETOWN,ownpid);
  265.     }
  266.     
  267.     /* We will get a SIGALRM signal at every MSPTICK milliseconds.
  268.        You may try to tweak its definiton in timer.h */
  269.     ualarm (100000,MSPTICK*1000);
  270. }
  271.  
  272. void
  273. ctick(p, v1, v2)        /* satisfy reference... */
  274. int p;
  275. void *v1, *v2;
  276. {
  277. }
  278.  
  279.  
  280. /* Called just before exiting to restore console state */
  281. void
  282. iostop()
  283. {
  284.     struct iface *ifp, *ifptmp;
  285.     void (**fp)();
  286.  
  287.     for(ifp = Ifaces; ifp != NULLIF; ifp = ifptmp){
  288.         ifptmp = ifp->next;
  289.         if_detach(ifp);
  290.     }
  291.  
  292.     for(fp = Shutdown; *fp != NULLVFP; fp++){
  293.         (**fp)();
  294.     }
  295.  
  296.     if(console_saved)
  297.         ioctl(console,TIOCSETP,&savecon);
  298.  
  299.     exit(0);
  300. }
  301.  
  302. /* Disable all "interrupts", don't mask any signals however */
  303. int dirps()
  304. {
  305.     int mask;
  306.     if (intoff)
  307.     return 0;
  308.     intoff = 1;
  309.     return 1;
  310. }
  311.  
  312. /* Restore the "interrupts" */
  313. void restore (mask)
  314.     char mask;
  315. {
  316.     if (mask) {
  317.     intoff = 0;
  318.     /* If we got a SIGIO when the interrupts where disabled, take care
  319.        of it now, by reissueing it. */
  320.     if (inputpending)
  321.         kill (ownpid, SIGIO); /* Argh */
  322.     }
  323. }
  324.  
  325. /* Return the interrupt state */
  326. int istate()
  327. {
  328.      return !intoff;
  329. }
  330.  
  331. /* Input interrupt handler.
  332.    This function is called whenever there is input from stdin, the
  333.    asynchronus interfaces or the NIT driver. But unfortunately only if their
  334.    respective input queues were empty.
  335.    Speeding up this function would probably enhance the general performance
  336.    of the program.
  337. */
  338. static void
  339. inpint()
  340. {
  341.     int i,ok,r,turn,cnt;
  342.     char i_state;
  343.     struct timeval timeout;
  344.     fd_set readfds;
  345.     
  346.     if (intoff) {
  347.         /* Interrupts are off, the input will be taken care of later */
  348.         inputpending = 1;
  349.         return;
  350.     }
  351.     inputpending = 0;
  352.     i_state = dirps();    /* turn off interrupts */
  353.     signal(SIGIO,inpint);  /* and reenable signals */
  354.     /* We use select() to se which file descriptors are ready for reading.
  355.        The syntax of select() differs between 4.2 and 4.3 BSD.
  356.      */
  357.     timeout.tv_sec = 0;
  358.     timeout.tv_usec = 35;
  359.     FD_ZERO (&readfds);
  360.     
  361.     /* This loop exits first when there is nothing to ready from the
  362.        asynchronus interfaces. */
  363.     for (turn=0;;++turn) {
  364.         for (i=0; i<Nasy; ++i)
  365.         FD_SET(Asy[i].IORser,&readfds);
  366. #ifdef PACKET
  367. /* This is only for the NIT and Tun drivers */
  368.         for (i=0; i<Nnit; ++i)
  369.         FD_SET(Nitdrvr[i].IOser,&readfds);
  370.         for (i=0; i<Ntun; ++i)
  371.         FD_SET(Tundrvr[i].IOser,&readfds);
  372. #endif
  373.         if(isatty(console))
  374.         FD_SET(console,&readfds);
  375.         ok = select(NOFILE,&readfds,(fd_set *)0,(fd_set *)0,&timeout);
  376.         cnt = 0;
  377.         if (ok > 0) {
  378. #ifdef PACKET
  379.         for (i=0; i<Nnit; ++i)
  380.             if (FD_ISSET(Nitdrvr[i].IOser,&readfds) && !turn)
  381.             psignal(&Nitdrvr[i],1);
  382.         for (i=0; i<Ntun; ++i)
  383.             if (FD_ISSET(Tundrvr[i].IOser,&readfds) && !turn)
  384.             psignal(&Tundrvr[i],1);
  385. #endif
  386.         /* Now scan the asynchronus interfaces. Remember, this is
  387.            supposed to be efficient. */
  388.         for (i=0; i<Nasy; ++i)
  389.             if (FD_ISSET(Asy[i].IORser,&readfds)) {
  390.             if (Asy[i].fifo.cnt == Asy[i].fifo.bufsize)
  391.                 continue; /* No room */
  392.             /* Try to read as much as we are allowed to */
  393.             r = read(Asy[i].IORser, Asy[i].fifo.wp,
  394.                  Asy[i].fifo.rp > Asy[i].fifo.wp ?
  395.                  Asy[i].fifo.rp - Asy[i].fifo.wp :
  396.                  &Asy[i].fifo.buf[Asy[i].fifo.bufsize] - Asy[i].fifo.wp);
  397.             if (r <= 0)
  398.                 continue;
  399.             cnt += r;
  400.             Asy[i].rxchar += r;
  401.             Asy[i].fifo.wp += r;
  402.             Asy[i].fifo.cnt += r;
  403.             if(Asy[i].fifo.wp >= &Asy[i].fifo.buf[Asy[i].fifo.bufsize])
  404.                 /* Wrap around */
  405.                 Asy[i].fifo.wp = Asy[i].fifo.buf;
  406.             /* Signal "asy_rx" that we have got new data. */
  407.             psignal(&Asy[i].fifo,1);
  408.             }
  409.         }
  410.         if (turn && cnt == 0){ /* To prevent endless loops */
  411.         restore(i_state);
  412.         return;
  413.         }
  414.         /* This function would be a monster if I didn't split it up
  415.            into a special part for keyboard input. */
  416.         if (ok > 0 && FD_ISSET(console,&readfds))
  417.         kbraw();
  418.        /* Now do it all over again since we might have received more input */
  419.     }
  420. }
  421. /* Read characters from stdin. Called from the generic interrupt handler. */
  422. int
  423. kbraw()
  424. {
  425.     int cnt;
  426.  
  427.     if (shell)
  428.      /* We are executing a shell right now */
  429.     return 0;
  430.  
  431.     if (Keyboard.cnt == Keyboard.bufsize)
  432.     return 0;
  433.     /* Try to read as much as we are allowed to */
  434.     cnt = read(console, Keyboard.wp,
  435.          Keyboard.rp > Keyboard.wp ? Keyboard.rp - Keyboard.wp :
  436.          Keyboard.buf + Keyboard.bufsize - Keyboard.wp);
  437.     if (cnt <= 0)
  438.     return 0;
  439.     Keyboard.cnt += cnt;
  440.     Keyboard.wp += cnt;
  441.     if(Keyboard.wp >= Keyboard.buf + Keyboard.bufsize)
  442.     Keyboard.wp = Keyboard.buf;
  443.     psignal(&Keyboard,1);
  444.     return cnt;
  445. }
  446. /* Blocking read from the keyboard */
  447. int
  448. kbread()
  449. {
  450.     int i_state;
  451.     char c;
  452.  
  453.     i_state = dirps();
  454.     while(Keyboard.cnt == 0)
  455.         pwait (&Keyboard);
  456.     c = *Keyboard.rp++;
  457.     if(Keyboard.rp == &Keyboard.buf[Keyboard.bufsize])
  458.         Keyboard.rp = Keyboard.buf;
  459.     Keyboard.cnt--;
  460.     restore(i_state);
  461.     
  462.     if (c == 0x7f) /* DEL key */
  463.         c = '\b';
  464.     if (c == '\n') /* Emulate MS/DOS. SysV would reset the ICRNL flag */
  465.         c = '\r';
  466.     return c;
  467. }
  468. void
  469. systick()
  470. {
  471. }
  472.  
  473. void
  474. sysreset()
  475. {
  476. }
  477.  
  478. /* timerint() is called at every clock tick. If interrupts are supposed
  479.    to be disabled, we do nothing except increasing Tick to keep the time
  480.    accurately. */
  481. static void
  482. timerint()        /* ctick() */
  483. {
  484.     ++Tick;
  485.     if (!intoff)
  486.     psignal(&Tick,1);
  487. }
  488. /* This function is only needed if you DO use alloc.c */
  489. unsigned long coreleft()
  490. {
  491.     struct rlimit rlp;
  492.     extern end;
  493.     getrlimit(RLIMIT_CORE,&rlp);
  494.     return ((unsigned long) (rlp.rlim_cur - end));
  495. }
  496. /* Sleep gracefully until the next interrupt. */
  497. void
  498. giveup()
  499. {
  500.     int old;
  501.     old = istate();
  502.     restore(1); /* Interrupts must be enabled */
  503.     sigpause(0);
  504.     if(old == 0) /* Interrupts were originally disabled */
  505.         dirps();
  506. }
  507. /* To be removed if alloc.c is to be used */
  508. memstat()
  509. {
  510.     return 0;
  511. }
  512.  
  513. /* Note: make sure that there is no previous definition of tolower() */
  514. char tolower (c)
  515.     char c;
  516. {
  517.     return ((c >= 'A' && c <= 'Z') ? c + 'a' - 'A' : c);
  518. }
  519.  
  520. FILE *
  521. tmpfile()
  522. {
  523.     FILE *tmp;
  524.     char *mktemp();
  525.     char *ptr = "SMTPXXXXXX";
  526.     char *name;
  527.     name = mktemp(ptr);
  528.     if ( ( tmp = fopen(name, "w+") ) == NULL)
  529.     {
  530.         tprintf("tmpfile: counld not create temp file.\n");
  531.         return(NULL);
  532.     }
  533.     (void) unlink(name);
  534.     return ( tmp );
  535. }
  536.  
  537. /* wildcard filename lookup */
  538. filedir(name, times, ret_str)
  539. char    *name;
  540. int    times;
  541. char    *ret_str;
  542. {
  543.     static char    dname[128], fname[128];
  544.     static DIR *dirp = NULL;
  545.     struct dirent *dp;
  546.     struct stat sbuf;
  547.     char    *cp, temp[128];
  548.  
  549.     /*
  550.      * Make sure that the NULL is there in case we don't find anything
  551.      */
  552.     ret_str[0] = '\0';
  553.  
  554.     if (times == 0) {
  555.         /* default a null name to *.* */
  556.         if (name == NULL || *name == '\0')
  557.             name = "*.*";
  558.         /* split path into directory and filename */
  559.         if ((cp = strrchr(name, '/')) == NULL) {
  560.             strcpy(dname, ".");
  561.             strcpy(fname, name);
  562.         } else {
  563.             strcpy(dname, name);
  564.             dname[cp - name] = '\0';
  565.             strcpy(fname, cp + 1);
  566.             /* root directory */
  567.             if (dname[0] == '\0')
  568.                 strcpy(dname, "/");
  569.             /* trailing '/' */
  570.             if (fname[0] == '\0')
  571.                 strcpy(fname, "*.*");
  572.         }
  573.         /* close directory left over from another call */
  574.         if (dirp != NULL)
  575.             closedir(dirp);
  576.         /* open directory */
  577.         if ((dirp = opendir(dname)) == NULL) {
  578.             tprintf("Could not open DIR (%s)\n", dname);
  579.             return;
  580.         }
  581.     } else {
  582.         /* for people who don't check return values */
  583.         if (dirp == NULL)
  584.             return;
  585.     }
  586.  
  587.     /* scan directory */
  588.     while ((dp = readdir(dirp)) != NULL) {
  589.         /* test for name match */
  590. /*        if (wildmat(dp->d_name, fname)) {*/
  591.         if (!strcmp(dp->d_name, fname) || (fname[0] == '*' &&
  592.             !strcmp(&dp->d_name[strlen(dp->d_name) - strlen(fname)+1],
  593.             &fname[1]))) { /* ...when we do not use wildmat */
  594.             /* test for regular file */
  595.             sprintf(temp, "%s/%s", dname, dp->d_name);
  596.             if (stat(temp, &sbuf) < 0)
  597.                 continue;
  598.             if ((sbuf.st_mode & S_IFREG) == 0)
  599.                 continue;
  600.             strcpy(ret_str, dp->d_name);
  601.             break;
  602.         }
  603.     }
  604.  
  605.     /* close directory if we hit the end */
  606.     if (dp == NULL) {
  607.         closedir(dirp);
  608.         dirp = NULL;
  609.     }
  610. }
  611. doshell(argc, argv)
  612. char **argv;
  613. {
  614.     register int pid, pid1, i;
  615.     void (*savi)();
  616.     int rc;
  617.     char str[256], *cp;
  618.     struct sgttyb ttybuf;
  619.     extern struct sgttyb savecon;
  620.     shell = 1;
  621.  
  622.     ioctl(console, TIOCGETP, &ttybuf);
  623.     ioctl(console, TIOCSETP, &savecon);
  624.  
  625.     str[0] = '\0';
  626.     for (i = 1; i < argc; i++) {
  627.         strcat(str, argv[i]);
  628.         strcat(str, " ");
  629.     }
  630.     if ((cp = getenv("SHELL")) == NULLCHAR)
  631.         cp = "/bin/sh";
  632.     if ((pid = fork()) == 0) {
  633.         seteuid(getuid()); /* Restore original user ID */
  634.         if (argc > 1)
  635.             (void)execl(cp, cp, "-c", str, 0);
  636.         else
  637.             (void)execl(cp, cp, (char *)0,(char *)0,0);
  638.         tprintf("Can't execl() (%d)\n", errno);
  639.         exit(1);
  640.     } else if (pid == -1) {
  641.         tprintf("Can't fork() (%d)\n", errno);
  642.         rc = -1;
  643.     } else {
  644.         savi = signal(SIGINT, SIG_IGN);
  645.         while ((pid1 = wait(&rc)) != pid && pid1 != -1)
  646.             ;    
  647.         signal(SIGINT, savi);
  648.     }
  649.     ioctl(console, TIOCSETP, &ttybuf);
  650.     shell = 0;
  651.     return (rc);
  652. }
  653.  
  654. dodir(argc, argv)
  655. char **argv;
  656. {
  657.     register int i;
  658.     char str[256];
  659.  
  660.     strcpy(str, "ls -lL ");
  661.     for (i = 1; i < argc; i++) {
  662.         strcat(str, argv[i]);
  663.         strcat(str, " ");
  664.     }
  665.  
  666.     return system(str);
  667. }
  668.     
  669. /* Terminal printf that counts newlines. At end of the page,
  670.  * prints "--More--" and waits for a keystroke before continuing.
  671.  */
  672. void
  673. display(i,v1,v2)
  674. int i;
  675. void *v1;
  676. void *v2;
  677. {
  678.     int c;
  679.     char i_state;
  680.     struct session *sp;
  681.  
  682.     /* This is very tricky code. Because the value of "Current" can
  683.      * change any time we do a pwait, we have to be careful to detect
  684.      * any change and go back and start again.
  685.      */
  686.     for(;;){
  687.         sp = Current;
  688.  
  689.         if(sp->morewait){
  690.             pwait(&sp->row);
  691.             if(sp != Current || sp->row <= 0){
  692.                 /* Current changed value, or the user
  693.                  * hasn't really hit a key
  694.                  */
  695.                 continue;
  696.             }
  697.             /* Erase the prompt */
  698.             printf("\r        \r");
  699.         }
  700.         sp->morewait = 0;
  701.         if((c = recvchar(sp->output)) == -1){
  702.             /* the alert() in swapscreen will cause this to
  703.              * return -1 when current changes
  704.              */
  705.             pwait(NULL);    /* Prevent a nasty loop */
  706.             continue;
  707.         }
  708.         fputc(c,stdout);
  709.         if(sp->record != NULLFILE){
  710.             fputc(c,sp->record);
  711.         }
  712.         if(sp->flowmode && c == '\n' && --sp->row <= 0){
  713.             printf("--More--");
  714.             sp->morewait = 1;
  715.         }
  716.     }
  717. }
  718. void swapscreen(old, new)
  719. struct session *old;
  720. struct session *new;
  721. {
  722.     char i_state;
  723.  
  724.     if(old == new)
  725.         return;    /* Nothing to do */
  726.  
  727.     fflush(stdout);
  728.     if(old != NULLSESSION){
  729.         /* Save old screen */
  730.     }
  731.     if(new != NULLSESSION){
  732.         /* Load new screen */
  733.     }
  734.     alert(Display,1);    /* Wake him up */
  735. }
  736. void
  737. newscreen(sp)
  738. struct session *sp;
  739. {
  740.     if(sp != NULLSESSION)
  741.         sp->screen = (struct screen *)callocw(1,sizeof(struct screen));
  742. }
  743. void
  744. freescreen(sp)
  745. struct session *sp;
  746. {
  747.     if(sp == NULLSESSION || sp->screen == NULLSCREEN)
  748.         return;
  749.     if(sp->screen->save != NULLCHAR)
  750.         free(sp->screen->save);
  751.     free((char *)sp->screen);
  752. }
  753.  
  754. /* Case-insensitive string comparison  (Needed on some machines) */
  755. int
  756. stricmp(a,b)
  757. register char *a,*b;
  758. {
  759.     char a1,b1;
  760.  
  761.     while((a1 = *a++) != '\0' && (b1 = *b++) != '\0'){
  762.         if(a1 == b1)
  763.             continue;    /* No need to convert */
  764.         if(isupper(a1))
  765.             a1 = tolower(a1);
  766.         if(isupper(b1))
  767.             b1 = tolower(b1);
  768.         if(a1 == b1)
  769.             continue;    /* NOW they match! */
  770.         if(a1 > b1)
  771.             return 1;
  772.         if(a1 < b1)
  773.             return -1;
  774.     }
  775.     return 0;
  776. }
  777.  
  778. /* Create directory */
  779. int
  780. domkd(argc,argv,p)
  781. int argc;
  782. char *argv[];
  783. void *p;
  784. {
  785.     if(mkdir(argv[1]) == -1)
  786.         tprintf("Can't make %s: %s\n",argv[1],sys_errlist[errno]);
  787.     return 0;
  788. }
  789. /* Remove directory */
  790. int
  791. dormd(argc,argv,p)
  792. int argc;
  793. char *argv[];
  794. void *p;
  795. {
  796.     if(rmdir(argv[1]) == -1)
  797.         tprintf("Can't remove %s: %s\n",argv[1],sys_errlist[errno]);
  798.     return 0;
  799. }
  800.  
  801. /* Routines we don't do... but don't want to constantly hack config.c */
  802. int
  803. dofkey(argc,argv,p)
  804. int argc;
  805. char *argv[];
  806. void *p;
  807. {
  808.     tprintf("This command is not supported under UNIX yet...\n");
  809.     return 0;
  810. }
  811.  
  812. int
  813. dobmail(argc,argv,p)
  814. int argc;
  815. char *argv[];
  816. void *p;
  817. {
  818.     tprintf("This command is not supported under UNIX yet...\n");
  819.     return 0;
  820. }
  821.  
  822. void rflush()
  823. {
  824.     char i_state;
  825.  
  826.     fflush(Rawterm);
  827. }
  828.  
  829. char Hashtab[256];
  830.  
  831. int16
  832. hash_ip(ipaddr)
  833. int32 ipaddr;
  834. {
  835.     return 0;    /* A nicer technique later on :-) KA9WSB */
  836. }
  837.  
  838. void
  839. kbint()
  840. {
  841. }
  842.  
  843. void
  844. uchtimer()
  845. {
  846. }
  847.  
  848. int32
  849. secclock()
  850. {
  851.     struct timeval tp;
  852.     int32 t, u;
  853.  
  854.     gettimeofday(&tp,NULL);
  855.     t = tp.tv_sec - StartSec;
  856.     u = tp.tv_usec - StartUsec;
  857.     if(u>499999)t++;
  858.     return t;
  859. }
  860.  
  861. int32
  862. msclock()
  863. {
  864.     struct timeval tp;
  865.     int32 t, u;
  866.  
  867.  
  868.     gettimeofday(&tp,NULL);
  869.     t = tp.tv_sec - StartSec;
  870.     u = tp.tv_usec - StartUsec;
  871.     return ((t * 1000) + (u / 1000));
  872. }
  873.  
  874. #ifdef BUFFERED_OUTPUT
  875. int FlushTock = 0;
  876. #ifndef TICKS_PER_FLUSH
  877. #define TICKS_PER_FLUSH 5
  878. #endif
  879. #endif
  880.  
  881. #ifdef MALLOCDEBUG
  882. int MallocTock = 0;
  883. #endif
  884.  
  885. void
  886. pctick()
  887. {
  888.     char i_state;
  889.  
  890.     Clock++;
  891.  
  892. #ifdef BUFFERED_OUTPUT
  893.     FlushTock++;
  894.     if(FlushTock>=TICKS_PER_FLUSH){
  895.         fflush(stdout);
  896.         fflush(stderr);
  897.         FlushTock = 0;
  898.     }
  899. #endif
  900.  
  901. #ifdef MALLOCDEBUG
  902.     MallocTock++;
  903.     if(MallocTock>=10){
  904.         i_state = dirps();    /* turn off interrupts */
  905.         if( malloc_verify() == 0 )
  906.             printf("Warning: malloc_verify: Corrupted heap!\n");
  907.         MallocTock = 0;
  908.         restore(i_state);
  909.     }
  910. #endif
  911. }
  912.  
  913.